Pular para o conteúdo principal

1. Two Sum

https://leetcode.com/problems/two-sum/description/

Definição

LLista de inteirosNN Cardinalidade (tamanho) de LTSoma esperadaiIˊndice atual da iterac¸a˜o\begin{align} L \coloneqq \text{Lista de inteiros}\\ N \coloneqq |N| \space \text{Cardinalidade (tamanho) de L}\\ T \coloneqq \text{Soma esperada}\\ i \coloneqq \text{Índice atual da iteração}\\ \end{align}

Intuição

A ideia é iterar LL e para cada índice ii devemos procurar outro índice jj que contenha um complemento C=L[j]C = L[j] então:

L[i]+C=TL[i]+L[j]=TL[i] + C = T \Rightarrow L[i] + L[j] = T

Para encontrar o complemento, usaremos uma tabela de consulta. Não precisamos pré-processar a lista LL para construir a tabela de consulta; podemos preenchê-la enquanto iteramos a lista.

Para o elemento atual L[i]L[i], procure na tabela uma entrada com o chave TL[i]T - L[i] que nos forneça um índice jj do complemento ou vazio. Se a entrada existir, retorne a resposta [i,j][i, j]; caso contrário, adicione a entrada L[i]iL[i] \Rightarrow i à tabela de consulta e repita o processo.

Ilustração

Lista de exemplo: [1, 2, 0, 4, 6]
Soma desejada: 5

1ª Iteração

Na primeira iteração ii começa no índice 0 e a tabela de consulta está vazia. O elemento atual é L[i]=L[0]=1L[i] = L[0] = 1, então devemos procurar o complemento C=T1=51=4C = T - 1 = 5 - 1 = 4, mas a tabela de consulta está vazia, então apenas adicionamos o elemento atual à tabela de consulta e incrementamos ii.

LinhaChaveValor
i
1
2
0
4
6

2ª iteração

O elemento atual é L[i]=L[1]=2L[i] = L[1] = 2, então devemos procurar o complemento C=T2=52=3C = T - 2 = 5 - 2 = 3, mas não há nenhuma entrada com a chave 33 na tabela, então apenas adicionamos o elemento atual à tabela de consulta e incrementamos ii.

LinhaChaveValor
110
i
1
2
0
4
6

3ª iteração

O elemento atual é L[i]=L[2]=0L[i] = L[2] = 0, então devemos procurar o complemento C=T0=50=5C = T - 0 = 5 - 0 = 5, mas não há nenhuma entrada com a chave 55 na tabela, então apenas adicionamos o elemento atual à tabela de consulta e incrementamos ii.

LinhaChaveValor
110
221
i
1
2
0
4
6

4ª iteração

O elemento atual é L[i]=L[3]=4L[i] = L[3] = 4, então devemos procurar o complemento C=T4=54=1C = T - 4 = 5 - 4 = 1 e ele existe na tabela na linha 11, que nos dá o índice 00, então a resposta é [0,i]=[0,3][0, i] = [0, 3]

LinhaChaveValor
110
221
302
i
1
2
0
4
6

Implementação

Clique para revelar a implementação
class Solution:
def twoSum(self, nums: list[int], target: int) -> list[int]:
visited_numbers: dict[int, int] = {}

for i, n in enumerate(nums):
complement_index = visited_numbers.get(target - n, None)

if complement_index is not None:
return [complement_index, i]

visited_numbers[n] = i

Testes

import pytest
from .solution import Solution


@pytest.mark.parametrize('numbers,target,expected', [
([0, 1], 1, [0, 1]),
([1, 2, 3], 5, [1, 2]),
])
def test_solution(numbers, target, expected):
result = Solution().twoSum(numbers, target)
assert result == expected

Time complexity

No pior caso, o complemento será encontrado no último índice, então precisamos iterar todos os elementos de entrada e preencher/consultar N1N - 1 da tabela. A iteração é O(n)O(n) e as inserções/consultas levam O(1)O(1) de tempo, supondo que não haja colisões. Portanto, a complexidade de tempo final é O(n)O(n).

Space complexity

No pior caso, precisamos preencher a tabela com N1N - 1 entradas, então a complexidade do espaço é O(N)O(N).